package org.gwt.grin.client.features;

import java.util.Map;

import org.gwt.grin.client.Feature;
import org.gwt.grin.client.util.Graphics;
import org.gwt.grin.client.util.Rectangle;

/**
 * Represents a clipped version of another feature. When painting, a clipping
 * rectangle is set.
 * 
 * @author Bill Foote (http://jovial.com)
 * @author ggeorg
 */
public class Clipped extends Modifier {

	protected Rectangle clipRegion;

	private Rectangle lastClipRegion = new Rectangle();
	private Rectangle tmpI = null;

	public Clipped(String name, Rectangle clipRegion, Feature part) {
		super(name, part);
		this.clipRegion = clipRegion;
	}

	@Override
	protected Feature createClone(Map<Feature, Feature> clones) {
		if (!isSetup()) {
			throw new IllegalStateException();
		}
		Clipped result = new Clipped(null, null, part.makeNewClone(clones));
		result.show = show; // FIXME
		if (clipRegion != null) {
			result.clipRegion = new Rectangle(clipRegion);
		}
		return result;
	}

	/**
	 * Change the region being clipped. This should only be called when it is
	 * safe to update the model (e.g. from a show command).
	 * 
	 * @param newRegion
	 *            the new clip region
	 */
	public void changeClipRegion(Rectangle newRegion) {
		clipRegion.x = newRegion.x;
		clipRegion.y = newRegion.y;
		clipRegion.width = newRegion.width;
		clipRegion.height = newRegion.height;
	}

	@Override
	public void paintFrame(Graphics gc) {
		lastClipRegion.x = Integer.MIN_VALUE;
		gc.getClipBounds(lastClipRegion);
		if (lastClipRegion.x == Integer.MIN_VALUE) {
			gc.setClipBounds(clipRegion);
			// part.markAsChanged();
			part.paintFrame(gc);
			gc.setClipBounds(null);
		} else {
			if (tmpI == null) {
				tmpI = new Rectangle(); // Holds intersection
			}
			tmpI.setBounds(lastClipRegion);
			if (tmpI.x < clipRegion.x) {
				tmpI.width -= clipRegion.x - tmpI.x;
				tmpI.x = clipRegion.x;
			}
			if (tmpI.y < clipRegion.y) {
				tmpI.height -= clipRegion.y - tmpI.y;
				tmpI.y = clipRegion.y;
			}
			if (tmpI.x + tmpI.width > clipRegion.x + clipRegion.width) {
				tmpI.width = clipRegion.x + clipRegion.width - tmpI.x;
			}
			if (tmpI.y + tmpI.height > clipRegion.y + clipRegion.height) {
				tmpI.height = clipRegion.y + clipRegion.height - tmpI.y;
			}
			if (tmpI.width > 0 && tmpI.height > 0) {
				gc.setClipBounds(tmpI);
				// part.markAsChanged();
				part.paintFrame(gc);
				gc.setClipBounds(lastClipRegion);
			}
		}
	}
}
